//! crates mod contains index, crates and rustup
//!
//!
//!
//!
//!

pub mod blobk_crates;
pub mod channel;
pub mod crates_file;
pub mod github_release;
pub mod index;
pub mod rustup;

#[derive(Clone, Default, Debug)]
pub enum DownloadMode {
    Init,
    // indicates this operation is fix error downloads
    Fix,
    #[default]
    Increment,
}
impl DownloadMode {
    pub fn new(init: bool, fix: bool) -> Self {
        if init {
            DownloadMode::Init
        } else if fix {
            DownloadMode::Fix
        } else {
            DownloadMode::Increment
        }
    }
}

pub mod utils {
    use std::path::{Path, PathBuf};

    use ring::digest::{Context, SHA256};
    use tokio::io::{AsyncReadExt, BufReader};

    use crate::errors::FreighterError;

    // the path rules of crates index file
    pub fn index_suffix(name: &str) -> String {
        match name.len() {
            1..=2 => format!("{}/{}", name.len(), name),
            3 => format!("{}/{}/{}", name.len(), &name[0..1], name),
            _ => format!("{}/{}/{}", &name[0..2], &name[2..4], name),
        }
    }

    // concate file_path with name and version
    pub fn get_file_path(crates_path: &Path, c_name: &str, c_version: &str) -> PathBuf {
        crates_path
            .join(c_name)
            .join(format!("{}-{}.crate", c_name, c_version))
    }

    pub async fn calculate_file_sha256(
        file_path: impl AsRef<Path>,
    ) -> Result<String, FreighterError> {
        let file = tokio::fs::File::open(file_path).await?;
        let mut reader = BufReader::new(file);

        let mut context = Context::new(&SHA256);

        let mut buffer = vec![0; 4096];
        loop {
            let count = reader.read(&mut buffer).await?;
            if count == 0 {
                break;
            }
            context.update(&buffer[..count]);
        }
        Ok(hex::encode(context.finish()))
    }
}

#[cfg(test)]
mod tests {
    use sha2::Digest;

    use crate::handler::utils;

    #[tokio::test]
    async fn test() -> tokio::io::Result<()> {
        let file_path = "./Cargo.toml";
        let sha256_str = match utils::calculate_file_sha256(file_path).await {
            Ok(sha256_str) => {
                println!("SHA-256 hash: {:?}", sha256_str);
                sha256_str
            }
            Err(e) => {
                eprintln!("Error calculating SHA-1:{:?}", e);
                String::new()
            }
        };

        let mut hasher = sha2::Sha256::new();
        let mut file = std::fs::File::open(file_path)?;
        std::io::copy(&mut file, &mut hasher)?;
        let result = hasher.finalize();
        let hex = format!("{:x}", result);
        println!("hex:{}", hex);
        assert_eq!(sha256_str, hex);
        Ok(())
    }
}
